/**
 * Copyright (c) 2018, dreamkaylee@foxmail.com All Rights Reserved.
*/

package com.limk.jconfig.realm;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

import com.common.shiro.bean.UserModel;
import com.common.shiro.realm.AbstractOperatorAuthorizingRealmWithRpn;
import com.limk.jconfig.entity.Permission;
import com.limk.jconfig.entity.Role;
import com.limk.jconfig.entity.User;
import com.limk.jconfig.service.SystemService;

/**
 * 自定义Realm
 * @author limk
 * @date 2018年2月13日 上午11:52:55
 * @version 1.0
 */
public class PpmsRealm extends AbstractOperatorAuthorizingRealmWithRpn {

	private static final Logger LOGGER = LogManager.getLogger(PpmsRealm.class);

	@Autowired
	private SystemService systemService;
	
	/**
	 * 无参构造
	 */
	public PpmsRealm() {
		super();
	}

	/**
	 * 构造函数，用于注入缓存和凭证
	 * @param cacheManager
	 * @param matcher
	 */
	public PpmsRealm(CacheManager cacheManager, CredentialsMatcher matcher) {
		super(cacheManager, matcher);
	}

	/**
	 * 仅支持UsernamePasswordToken类型的Token
	 * @param token
	 * @return
	 * @see org.apache.shiro.realm.AuthenticatingRealm#supports(org.apache.shiro.authc.AuthenticationToken)
	 */
	@Override
	public boolean supports(AuthenticationToken token) {
		return token instanceof UsernamePasswordToken;
	}

	/**
	 * 授权
	 * @param principals
	 * @return
	 * @see org.apache.shiro.realm.AuthorizingRealm#doGetAuthorizationInfo(org.apache.shiro.subject.PrincipalCollection)
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		LOGGER.debug("=====Shiro授权认证开始=====");
		SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
		UserModel userModel = (UserModel) principals.getPrimaryPrincipal();
		authorizationInfo.addRoles(userModel.getRoles());
		authorizationInfo.addStringPermissions(userModel.getPercodes());
		LOGGER.debug("=====Shiro授权认证结束=====");
		return authorizationInfo;
	}

	/**
	 * 认证
	 * @param authenticationToken
	 * @return
	 * @throws AuthenticationException
	 * @see org.apache.shiro.realm.AuthenticatingRealm#doGetAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken)
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
			throws AuthenticationException {
		LOGGER.debug("=====Shiro登录认证开始=====");
		int one = 1, two = 2;
		UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
		User user = systemService.selectUserByUserName(token.getUsername());
		if (user == null) {
			throw new UnknownAccountException();
		} else if (user.getLocked() == one) {
			throw new DisabledAccountException();
		} else if (user.getLocked() == two) {
			throw new LockedAccountException();
		} else {
			List<Role> roles = systemService.selectRolesByUserId(user.getId());
			List<String> roleIdentifys = new ArrayList<>();
			List<Permission> permissions = new ArrayList<Permission>();
			for (Role role : roles) {
				if (role != null) {
					List<Permission> list = systemService.selectPermissionByRoleId(role.getId());
					permissions.addAll(list);
				}
				roleIdentifys.add(role.getIdentify());
			}
			List<Integer> permissionids = new ArrayList<>();
			List<String> percodes = new ArrayList<>();
			for (Permission permission : permissions) {
				permissionids.add(permission.getId());
				percodes.add(permission.getPercode());
			}
			UserModel model = new UserModel();
			model.setUserId(user.getId());
			model.setUserName(user.getUsername());
			model.setRoles(roleIdentifys);
			model.setPermissions(permissionids);
			model.setPercodes(percodes);
			model.setIp(token.getHost());
			model.setLogontime(new Date());
			SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(model, user.getPassword(),
					ByteSource.Util.bytes(user.getSalt()), this.getName());
			Subject currentUser = SecurityUtils.getSubject();
			Session session = currentUser.getSession();
			session.setAttribute("userModel", model);
			LOGGER.info("=====Shiro登录认证结束=====");
			return simpleAuthenticationInfo;
		}
	}

	/**
	 * 退出
	 * @param principals
	 * @see org.apache.shiro.realm.CachingRealm#onLogout(org.apache.shiro.subject.PrincipalCollection)
	 */
	@Override
	public void onLogout(PrincipalCollection principals) {
		super.clearCachedAuthorizationInfo(principals);
		UserModel userModel = (UserModel) principals.getPrimaryPrincipal();
		this.clearUserCache(userModel);
	}

	@Override
	public void setName(String name) {
		super.setName("ppmsRealm");
	}

	/**
	 * 清除用户缓存
	 * @param userModel
	 */
	public void clearUserCache(UserModel userModel) {
		clearUserCache(userModel.getUserName());
	}

	/**
	 * 清除用户缓存
	 * @param userName
	 */
	public void clearUserCache(String userName) {
		SimplePrincipalCollection principals = new SimplePrincipalCollection();
		principals.add(userName, super.getName());
		super.clearCachedAuthenticationInfo(principals);
	}

	/**
	 * 清除缓存
	 */
	public void clearCached() {
		PrincipalCollection principals = SecurityUtils.getSubject().getPrincipals();
		super.clearCache(principals);
	}

}
